/* hal_spi.h */
#ifndef __HAL_SPI_H__
#define __HAL_SPI_H__

#include "hal_common.h"

/* SPI hardware flags & interrupts. */
#define SPI_FLAG_RX_REQ  SPI_STS_RXIF_MASK
#define SPI_FLAG_TX_REQ  SPI_STS_TXIF_MASK
#define SPI_FLAG_FRAME_DONE    SPI_STS_FCIF_MASK
#define SPI_FLAG_TX_DONE       SPI_STS_TCIF_MASK
#define SPI_FLAG_TX_UNDERFLOW  SPI_STS_TXUNIF_MASK
#define SPI_FLAG_RX_OVERFLOW   SPI_STS_RXOVIF_MASK
#define SPI_FLAG_MATCH         SPI_STS_MATIF_MASK
#define SPI_FLAG_RX_FRAME_START   SPI_STS_SOF_MASK
#define SPI_FLAG_RX_EMPTY      SPI_STS_RXEPT_MASK
#define SPI_FLAG_BUSY          SPI_STS_BUSY_MASK

typedef enum
{
    SPI_PolarityPhase_Alt0 = 0u,
	SPI_PolarityPhase_Alt1 = 1u,
	SPI_PolarityPhase_Alt2 = 2u,
	SPI_PolarityPhase_Alt3 = 3u,
} SPI_PolarityPhase_Type;

/* TBD. */
typedef enum
{
    SPI_MatchMode_Disabled = 0u,
    SPI_MatchMode_1stDataOnMatch0OrMatch1,
    SPI_MatchMode_AnyDataOnMatch0OrMatch1,
    SPI_MatchMode_1stDataOnMatch0And2ndOnMatch1,
} SPI_MatchMode_Type;

typedef struct
{
    SPI_MatchMode_Type Mode;
    uint32_t Match0;
    uint32_t Match1;
} SPI_RxMatchConf_Type;

typedef struct
{
    uint32_t DivFromClkSrc;
    uint32_t DelayBetweenFrames;
    uint32_t DelayFromPcsToSck;    
    uint32_t DelayFromSckToPcs;
} SPI_ClkTimingConf_Type;

typedef enum
{
    SPI_PcsActiveMode_Low = 0u,
    SPI_PcsActiveMode_High,
} SPI_PcsActiveMode_Type;

typedef struct
{
    uint32_t ClkSrcFreq;       /* freq of clock source. */
	uint32_t BaudrateBaseFreq; /* freq of spi bus communication. */

    bool EnableHighzOutputOnIdle; /* SPI data output line in high z mode when chip select is negated, or it will keep the last state. */

    uint32_t TxFifoWatermark;
    uint32_t RxFifoWatermark;
} SPI_MasterInit_Type;

typedef struct
{
    bool EnableAutoPcs; /* enable the internal pcs from the clock line regardless of hardware pcs line. */
    bool EnableHighzOutputOnIdle; /* SPI data output line in high z mode when chip select is negated, or it will keep the last state. */
    //SPI_PcsActiveMode_Type PcsActiveMode;
    uint32_t TxFifoWatermark;
    uint32_t RxFifoWatermark;
} SPI_SlaveInit_Type;

typedef enum
{
    SPI_Prescale_Div1 = 0u,
    SPI_Prescale_Div2,
    SPI_Prescale_Div4,
    SPI_Prescale_Div8,
    SPI_Prescale_Div16,
    SPI_Prescale_Div32,
    SPI_Prescale_Div64,
    SPI_Perscale_Div128,
} SPI_Prescale_Type;

#if 0
typedef enum
{
    SPI_PcsAlt_0 = 0u,
    SPI_PcsAlt_1,
    SPI_PcsAlt_2,
    SPI_PcsAlt_3,
} SPI_PcsAlt_Type;
#endif

typedef enum
{
    SPI_XferMode_TxRx = 0u,
    SPI_XferMode_TxOnly, /*!< rx data would be ignored, with no data goes into rx fifo. */
    SPI_XferMode_RxOnly, /*!< spi peripheral would generate the clock automatiacally after the cmd, no need to tx data for receving data. */
} SPI_XferMode_Type;

typedef enum
{
    SPI_DataBitOrder_MSB = 0u,
    SPI_DataBitOrder_LSB = 1u
} SPI_DataBitOrder_Type;

/* define tx config command.
 * a spi transfer would starts from a tx config command, with the following data stream. */
typedef struct
{
    SPI_PolarityPhase_Type PolarityPhase;
    SPI_Prescale_Type Prescale; /* this frame's sck clock from spi func clock. */
    //SPI_PcsAlt_Type PcsAlt; /* select 1 in 4 channel. */
    SPI_PcsActiveMode_Type PcsActiveMode;
    //bool EnableLsb; /* most last bit would be transfered, or the MSB. */
    SPI_DataBitOrder_Type DataBitOrder;
    bool EnableByteSwap;
    //bool EnableKeepPcs;
    uint32_t FrameBits; /* 1 - 4096. */
    SPI_XferMode_Type XferMode;
} SPI_XferChannelConf_Type; /* SPI_TxFrameConf_Type */

void SPI_InitMaster(SPI_Type * base, SPI_MasterInit_Type * init);
void SPI_InitSlave(SPI_Type * base, SPI_SlaveInit_Type * init);

void SPI_EnableInterrupts(SPI_Type * base, uint32_t flags);
void SPI_DisableInterrupts(SPI_Type * base, uint32_t flags);

void SPI_EnableTxDma(SPI_Type * base, bool enable);
void SPI_EnableRxDma(SPI_Type * base, bool enable);
uint32_t SPI_GetStatusFlags(SPI_Type * base);
void SPI_ClearStatusFlags(SPI_Type * base, uint32_t flags);

//void SPI_SetTxFrameConf(SPI_Type * base, SPI_TxFrameConf_Type * cmd);

void SPI_ActiveXferChannel(SPI_Type * base, uint32_t channel, SPI_XferChannelConf_Type * conf);
void SPI_RequestKeepPcs(SPI_Type * base, bool enable);

void SPI_PutFifoDataIn(SPI_Type * base, uint32_t dat);
uint32_t SPI_GetFifoDataOut(SPI_Type * base);

void SPI_SetClkTimingConf(SPI_Type * base, SPI_ClkTimingConf_Type * conf);

void SPI_ResetTxFifo(SPI_Type * base);

#endif /* __HAL_SPI_H__ */

